package wordit.ea;

import java.util.Properties;

import wordit.ea.selectionfunctions.TournamentSelectionFunction;
import wordit.ea.stopfunctions.MaximumGenerationsStopFunction;

public class Configuration {

	private GenomeFactory genomeFactory;
	private FitnessFunction fitnessFunction;
	private MutationFunction mutationFunction;
	private CrossoverFunction crossoverFunction;
	private SelectionFunction selectionFunction;
	private StopFunction stopFunction;
	private int generationSize;
	private int trialsCount;

	public void setGenomeFactory(GenomeFactory genomeFactory) {
		this.genomeFactory = genomeFactory;
	}

	public GenomeFactory getGenomeFactory() {
		return genomeFactory;
	}

	public void setFitnessFunction(FitnessFunction fitnessFunction) {
		this.fitnessFunction = fitnessFunction;
	}

	public FitnessFunction getFitnessFunction() {
		return fitnessFunction;
	}

	public void setMutationFunction(MutationFunction mutationFunction) {
		this.mutationFunction = mutationFunction;
	}

	public MutationFunction getMutationFunction() {
		return mutationFunction;
	}

	public void setCrossoverFunction(CrossoverFunction crossoverFunction) {
		this.crossoverFunction = crossoverFunction;
	}

	public CrossoverFunction getCrossoverFunction() {
		return crossoverFunction;
	}

	public void setSelectionFunction(SelectionFunction selectionFunction) {
		this.selectionFunction = selectionFunction;
	}

	public SelectionFunction getSelectionFunction() {
		return selectionFunction;
	}

	public void setStopFunction(StopFunction stopFunction) {
		this.stopFunction = stopFunction;
	}

	public StopFunction getStopFunction() {
		return stopFunction;
	}

	public void setGenerationSize(int generationSize) {
		this.generationSize = generationSize;
	}

	public int getGenerationSize() {
		return generationSize;
	}

	public void readFromArguments(String[] args) {
		Properties props = parseArguments(args);

		if (props.containsKey("GenerationSize"))
			setGenerationSize(Integer.parseInt(props
					.getProperty("GenerationSize")));

		if (props.containsKey("MutationProbability"))
			setMutationProbability(Double.parseDouble(props
					.getProperty("MutationProbability")));

		if (props.containsKey("TournamentSize"))
			setTournamentSize(Integer.parseInt(props
					.getProperty("TournamentSize")));
		
		if (props.containsKey("MaximumGenerations"))
			setMaximumGenerations(Integer.parseInt(props
					.getProperty("MaximumGenerations")));
		
		if (props.containsKey("TrialsCount"))
			setTrialsCount(Integer.parseInt(props
					.getProperty("TrialsCount")));
	}

	private void setMaximumGenerations(int n) {
		if (getStopFunction() == null)
			throw new IllegalStateException("Stop function not set");

		if (!(getStopFunction() instanceof MaximumGenerationsStopFunction))
			throw new IllegalStateException(
					"Stop function is not a MaximumGenerationsStopFunction");
		
		((MaximumGenerationsStopFunction) getStopFunction()).setMaximumGenerations(n);
	}

	private void setTournamentSize(int n) {
		if (getSelectionFunction() == null)
			throw new IllegalStateException("Selection function not set");

		if (!(getSelectionFunction() instanceof TournamentSelectionFunction))
			throw new IllegalStateException(
					"Selection function is not a TournamentSelectionFunction");

		((TournamentSelectionFunction) getSelectionFunction())
				.setTournamentSize(n);
	}

	private void setMutationProbability(double p) {
		if (getMutationFunction() == null)
			throw new IllegalStateException("Mutation function not set");

		getMutationFunction().setMutationProbability(p);
	}

	private Properties parseArguments(String[] args) {
		Properties p = new Properties();
		int i = 0;

		while (i < args.length) {
			String key, value;

			key = args[i];
			i++;

			if (i >= args.length)
				throw new IllegalArgumentException("no value for argument "
						+ key);

			value = args[i];
			i++;

			p.put(key, value);
		}

		return p;
	}

	public String toString() {
		String tournamentSize, maximumGenerations;

		try {
			tournamentSize = String.valueOf(getTournamentSize());
		} catch (IllegalStateException e) {
			tournamentSize = "N/A";
		}
		
		try {
			maximumGenerations = String.valueOf(getMaximumGenerations());
		} catch (IllegalStateException e) {
			maximumGenerations = "N/A";
		}
		
		return String.format("TrialsCount=%d\nMutationProbability=%f\n" + "GenerationSize=%d\n"
				+ "TournamentSize=%s\nMaximumGenerations=%s\n", getTrialsCount(), getMutationFunction()
				.getMutationProbability(), getGenerationSize(), tournamentSize, maximumGenerations);
	}

	private int getMaximumGenerations() {
		if (getSelectionFunction() == null)
			throw new IllegalStateException("Selection function not set");

		if (!(getSelectionFunction() instanceof TournamentSelectionFunction))
			throw new IllegalStateException(
					"Selection function is not a TournamentSelectionFunction");

		return ((MaximumGenerationsStopFunction) getStopFunction()).getMaximumGenerations();
	}

	private int getTournamentSize() {
		if (getSelectionFunction() == null)
			throw new IllegalStateException("Selection function not set");

		if (!(getSelectionFunction() instanceof TournamentSelectionFunction))
			throw new IllegalStateException(
					"Selection function is not a TournamentSelectionFunction");

		return ((TournamentSelectionFunction) getSelectionFunction())
				.getTournamentSize();
	}

	public void setTrialsCount(int i) {
		this.trialsCount = i;
	}

	public int getTrialsCount() {
		return trialsCount;
	}
}
